package oa.game;

import java.sql.SQLException;
import java.util.*;

public class Juego {

    private static final String[] colores = new String[]{"BLUE", "RED"};
    private boolean valido;
    private int duracion;
    private int tiempoInicio;
    private String equipoGanador;
    private final DBUtils dbUtils;
    private final List<Muerte> muertes;
    private final List<PuntosJugador> puntosJugador;
    private Map<String, String> parametrosJuego;
    private final Map<String, List<Integer>> capturadoresEnJuego;
    private final List<EventoBandera> eventosBandera;
    private final Map<String, Set<Integer>> equipos;

    public void setTiempoFin(int tiempoFin) {
        duracion = tiempoFin - tiempoInicio;

        if (duracion < 0) {
            duracion++;
        }
    }

    public void setTiempoInicio(int tiempoInicio) {
        this.tiempoInicio = tiempoInicio;
    }

    public void setParametros(Map<String, String> parametrosJuego) {
        this.parametrosJuego = parametrosJuego;
    }

    public void setGanadores(String team) {
        equipoGanador = team;
    }

    private String contrario(String iterEquipo) {
        if ("RED".equals(iterEquipo)) {
            return "BLUE";
        } else if ("BLUE".equals(iterEquipo)) {
            return "RED";
        } else {
            return null;
        }
    }

    private static class Muerte {

        private final int idKiller;
        private final int idVictim;
        private final int idArma;

        public Muerte(int idKiller, int idVictim, int idArma) {
            this.idKiller = idKiller;
            this.idVictim = idVictim;
            this.idArma = idArma;
        }
    }

    private static class EventoBandera {

        private AccionesBandera accion;
        private List<Integer> jugadores;    // ordenado
        private Integer segundos;
        private String equipo;

        public EventoBandera(AccionesBandera accion, List<Integer> jugadores, Integer segundos, String equipo) {
            this.accion = accion;
            this.jugadores = jugadores;
            this.segundos = segundos;
            this.equipo = equipo;
        }
    }

    private static class PuntosJugador {

        private final int idPlayer;
        private final int puntos;
        private final int time;

        public PuntosJugador(int idPlayer, int intPuntos, int secondsTime) {
            this.idPlayer = idPlayer;
            this.puntos = intPuntos;
            this.time = secondsTime;
        }
    }

    public Juego(DBUtils dbUtils) {
        this.dbUtils = dbUtils;
        muertes = new ArrayList<Muerte>();
        puntosJugador = new ArrayList<PuntosJugador>();
        valido = false;
        eventosBandera = new ArrayList<EventoBandera>();
        capturadoresEnJuego = new HashMap<String, List<Integer>>();
        equipos = new HashMap<String, Set<Integer>>();

        for (String string : colores) {
            equipos.put(string, new HashSet<Integer>());
        }
    }

    public void cargarMuerte(int idKiller, int idVictim, int idArma) {
        muertes.add(new Muerte(idKiller, idVictim, idArma));
    }

    public void salvarJuego() throws SQLException {
        if (!valido) {
            return;
        }

        int gameId = dbUtils.crearJuego(duracion, equipoGanador);

        for (Map.Entry<String, String> entry : parametrosJuego.entrySet()) {
            dbUtils.crearParametro(gameId, entry.getKey(), entry.getValue());
        }

        for (Muerte muerte : muertes) {
            dbUtils.crearMuerte(gameId, muerte.idKiller, muerte.idVictim, muerte.idArma);
        }

        for (PuntosJugador pj : puntosJugador) {
            dbUtils.crearPuntosJugador(gameId, pj.idPlayer, pj.puntos, pj.time);
        }

        for (EventoBandera evento : eventosBandera) {
            for (Integer jugador : evento.jugadores) {
                dbUtils.crearEvento(gameId,evento.accion,evento.equipo,evento.segundos,jugador,evento.jugadores.indexOf(jugador));
            }
        }

        for (Map.Entry<String, Set<Integer>> entry : equipos.entrySet()) {
            for (Integer jugador : entry.getValue()) {
                dbUtils.crearEquipo(gameId,entry.getKey(),jugador);
            }
        }
    }

    public void addPuntosJugador(int idPlayer, int intPuntos, int secondsTime) {
        puntosJugador.add(new PuntosJugador(idPlayer, intPuntos, secondsTime));
    }

    public boolean isValido() {
        return valido;
    }

    public void setValido(boolean valido) {
        this.valido = valido;
    }

    public void cargarAccionBandera(int jugador, AccionesBandera accion, int segundos, String linea) {

        List<Integer> actuales = null;

        String equipo = null;
        for (String iterEquipo : colores) {
            if (linea.contains(iterEquipo.toString())) {
                switch (accion) {
                    case CAPTURED_FLAG:
                        equipo = contrario(iterEquipo);
                        actuales = this.capturadoresEnJuego.get(equipo);
                        this.capturadoresEnJuego.put(equipo, new ArrayList<Integer>());
                        break;
                    case GOT_FLAG:
                        equipo = contrario(iterEquipo);

                        if (!this.capturadoresEnJuego.containsKey(equipo)) {
                            this.capturadoresEnJuego.put(equipo, new ArrayList<Integer>());
                        }
                        actuales = this.capturadoresEnJuego.get(equipo);
                        actuales.add(jugador);
                        break;
                    case FRAGGED_CARRIER:
                        equipo = contrario(iterEquipo);
                        actuales = new ArrayList<Integer>();
                        actuales.add(jugador);
                        break;
                    case RETURNED_FLAG:
                        equipo = iterEquipo;
                        actuales = new ArrayList<Integer>();
                        actuales.add(jugador);
                        this.capturadoresEnJuego.put(contrario(iterEquipo), new ArrayList<Integer>());
                        break;
                }
            }
        }

        if (equipo != null) {
            this.equipos.get(equipo).add(jugador);
            this.equipos.get(contrario(equipo)).remove(jugador);
        }

        this.eventosBandera.add(new EventoBandera(accion, actuales, segundos - this.tiempoInicio, equipo));
    }
}
